package Main;
import com.cloudgarden.resource.SWTResourceManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class Main {
        private String divider="/"; //!!!divider in path
        private Document doc=null; // the loaded XML document
        private Element curRoot=null; //represents the element in current path
        private String xmlFile="";
        private String dtd="";
        private String prevPath="";
        private String errors="";
        private int scrollIndex=0; // represents the index of the current scrolling range
        private int selectionIndex=-1; // represents the index of the currently selected node in the list
        private boolean nodeSelected = false; // true if any node in the current node list is selected
        //==========GUI stuff===========
        private Shell sShell = null;
        private Label label1;
        private Button button6;
        private Label label7;
        private TreeMap<String,String> currNodes = new TreeMap<String,String>();
        private Button button7;
        private Button button5;
        private Button[] buttons = new Button[5];
        private List list2;
        private List list1;
        private Button button4;
        private Button button3;
        private Text text3;
        private Label label6;
        private Button button2;
        private Label label5;
        private Label label4;
        private Label label3;
        private Text text2;
        private Text text1;
        private Label label2;
        private Button button1;
        private SelectionListener itemListener;
        private Label label9;
        private Label label8;
        private Label label10;
        private Label label11;
        private List list4;
        private List list3; 
        private ScrollBar scroll1;
        private ScrollBar scroll2;
        private ScrollBar scroll3;
        private ScrollBar scroll4;
        //private Image bg;

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                /* Before this is run, be sure to set up the launch configuration (Arguments->VM Arguments)
                 * for the correct SWT library path in order to run with the SWT dlls. 
                 * The dlls are located in the SWT plugin jar.  
                 * For example, on Windows the Eclipse SWT 3.1 plugin jar is:
                 *       installation_directory\plugins\org.eclipse.swt.win32_3.1.0.jar
                 */
                Display display = Display.getDefault();
                Main thisClass = new Main();
                thisClass.createSShell();
                thisClass.sShell.open();

                while (!thisClass.sShell.isDisposed()) {
                        if (!display.readAndDispatch())
                                display.sleep();
                }
                display.dispose();
        }

        /**
         * This method initializes sShell
         */
        private void createSShell() {
                File f = new File("");
                String go=new String(f.getAbsolutePath());
                Image bg=new Image(Display.getDefault(),go+"/image.jpg");
                sShell = new Shell(Display.getDefault(),SWT.CLOSE|SWT.MIN);

                {
                        //Register as a resource user - SWTResourceManager will
                        //handle the obtaining and disposing of resources
                        SWTResourceManager.registerResourceUser(sShell);
                }
                
                sShell.setText("XML Browser");
                sShell.setBackgroundImage(bg);          
                sShell.setSize(542, 513);
                sShell.setLayout(null);

                {
                        button1 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button1.setText("Open XML");
                        button1.setBounds(17, 25, 76, 29);
                        button1.setBackgroundImage(bg);
                        button1.addSelectionListener(new SelectionAdapter() {
                                public void widgetSelected(SelectionEvent evt) {
                                        try {
                                                button1WidgetSelected(evt);
                                        }                               
                                              catch ( SAXParseException spe ) {
                                                  label7.setText("XML Parse Failed");
                                               }

                                               catch ( SAXException se ) {
                                                   System.out.println("SAX exception");
                                                  se.printStackTrace();         
                                               }

                                               catch ( FileNotFoundException fne ) {
                                                   label7.setText("DTD file not found");
                                               }
                                               catch (Exception e) {
                                                                if(!errors.equals(""))
                                                                {
                                                                        button6.setVisible(true);
                                                                }       

                                                                else {
                                                                // TODO Auto-generated catch block
                                                                        label7.setText("XML Parse Failed");
                                                                        //e.printStackTrace();
                                                                 }
                                                        }
                                            }
                        });
                }
                {
                        label1 = new Label(sShell, SWT.RIGHT);
                        label1.setText("Current Path:");
                        label1.setBounds(152, 28, 101, 21);
                        label1.setBackgroundImage(bg);
                        label1.setForeground(SWTResourceManager.getColor(255,255,255));
                }
                {
                        label2 = new Label(sShell, SWT.RIGHT | SWT.WRAP);
                        label2.setText("Relative Expression:");
                        label2.setBounds(147, 68, 106, 21);
                        label2.setBackgroundImage(bg);
                        label2.setForeground(SWTResourceManager.getColor(255,255,255));
                }
                {
                        text1 = new Text(sShell, SWT.BORDER);
                        text1.setBounds(258, 28, 222, 21);
                        text1.setEnabled(false);
                        text1.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(text1.getText());
                                }
                        });
                        text1.addFocusListener(new FocusAdapter() {
                                public void focusGained(FocusEvent evt) {
                                        text1FocusGained(evt);
                                }});
                        
                        text1.addFocusListener(new FocusAdapter() {
                                public void focusLost(FocusEvent evt) {
                                        text1FocusLost(evt);
                                }});
                }
                {
                        text2 = new Text(sShell, SWT.BORDER);
                        text2.setBounds(259, 68, 222, 21);
                        text2.setEditable(false);
                        text2.setEnabled(false);
                        text2.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(text2.getText());
                                }
                        });
                }
                {
                        label3 = new Label(sShell, SWT.CENTER | SWT.WRAP);
                        label3.setText("Current Node List:");
                        label3.setBounds(61, 98, 101, 21);
                        label3.setBackgroundImage(bg);
                        label3.setForeground(SWTResourceManager.getColor(255,255,255));
                }
                {
                        label4 = new Label(sShell, SWT.LEFT | SWT.WRAP);
                        label4.setText("Elements:");
                        label4.setBounds(10, 188, 92, 21);
                        label4.setBackgroundImage(bg);
                        label4.setForeground(SWTResourceManager.getColor(255,255,255));
                }
                {
                        label5 = new Label(sShell, SWT.LEFT | SWT.WRAP);
                        label5.setText("Values:");
                        label5.setBounds(111, 188, 101, 21);
                        label5.setBackgroundImage(bg);
                        label5.setForeground(SWTResourceManager.getColor(255,255,255));
                }
                {
                        button2 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button2.setText("Back");
                        button2.setBackgroundImage(bg);
                        button2.setEnabled(false);
                        button2.setBounds(200, 425, 91, 30);
                        button2.addSelectionListener(new SelectionAdapter() {
                                public void widgetSelected(SelectionEvent evt) {
                                        try {
                                                button2WidgetSelected(evt);
                                        } catch (Exception e) {e.printStackTrace();}                                    
                                }
                        });
                }
                {
                        label6 = new Label(sShell, SWT.RIGHT | SWT.WRAP);
                        label6.setText("Name/Value:");
                        label6.setBounds(152, 156, 101, 21);
                        label6.setBackgroundImage(bg);
                        label6.setForeground(SWTResourceManager.getColor(255,255,255));
                }
                {
                        text3 = new Text(sShell, SWT.BORDER);
                        text3.setBounds(258, 156, 222, 21);
                        text3.setEnabled(false);
                        text3.setEditable(false);
                        text3.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(text3.getText());
                                }
                        });

                }
                {
                        button3 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button3.setText("<");
                        button3.setBackgroundImage(bg);
                        button3.setBounds(13, 119, 37, 28);
                        button3.setEnabled(false);
                        button3.addSelectionListener(new SelectionAdapter() {
                                public void widgetSelected(SelectionEvent evt) {
                                        try {
                                                button3WidgetSelected(evt);
                                        } catch (Exception e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                }
                        });
                }
                {
                        button4 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button4.setText(">");
                        button4.setBackgroundImage(bg);
                        button4.setBounds(475, 119, 39, 28);
                        button4.setEnabled(false);
                        button4.addSelectionListener(new SelectionAdapter() {
                                public void widgetSelected(SelectionEvent evt) {
                                        try {
                                                button4WidgetSelected(evt);
                                        } catch (Exception e) {e.printStackTrace();}
                                }
                        });
                }
                {
                        list1 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
                        list1.setBounds(10, 216, 92, 207);
                        list1.setEnabled(false);
                        scroll1=list1.getVerticalBar();
                        scroll1.addListener (SWT.Selection, new Listener () {
                                public void handleEvent (Event event) {
                                        scroll2.setSelection(scroll1.getSelection());
                                        list2.setTopIndex(list1.getTopIndex());
                                }
                        });
                        list1.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                        });
                        list1.addMouseMoveListener(new MouseMoveListener() {
                                public void mouseMove(MouseEvent evt) {
                                        //System.out.println(evt);
                                        int element;
                                        //compute at which element of the list mouse cursor is
                                        element=scroll1.getSelection()+evt.y/list1.getItemHeight();
                                        if(element>=list1.getItemCount()){
                                                label11.setText("");
                                        }
                                        else{
                                                label11.setText(list1.getItem(element));
                                        }
                                }
                        });
                }
                {
                        list2 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
                        list2.setBounds(110, 216, 144, 207);
                        list2.setSelection(new java.lang.String[] {""});
                        list2.setEnabled(false);
                        scroll2=list2.getVerticalBar();
                        scroll2.addListener (SWT.Selection, new Listener () {
                                public void handleEvent (Event event) {
                                        scroll1.setSelection(scroll2.getSelection());
                                        list1.setTopIndex(list2.getTopIndex());
                                }
                        });
                        list2.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                        });
                        list2.addMouseMoveListener(new MouseMoveListener() {
                                public void mouseMove(MouseEvent evt) {
                                        int element;
                                        //compute at which element of the list mouse cursor is
                                        element=scroll2.getSelection()+evt.y/list2.getItemHeight();
                                        if(element>=list2.getItemCount()){
                                                label11.setText("");
                                        }
                                        else{
                                                label11.setText(list2.getItem(element));
                                        }
                                }
                        });
                }               
                {
                        button5 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button5.setText("Forward");
                        button5.setBackgroundImage(bg);
                        button5.setBounds(291, 425, 91, 30);
                        button5.setEnabled(false);
                        button5.addSelectionListener(new SelectionAdapter() {
                                public void widgetSelected(SelectionEvent evt) {
                                        try {
                                                button5WidgetSelected(evt);
                                        } catch (Exception e) {e.printStackTrace();}
                                }
                        });
                }
                {
                        buttons[0] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
                        buttons[0].setBounds(68, 125, 78, 22);
                        buttons[0].setBackgroundImage(bg);
                        buttons[0].addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(buttons[0].getToolTipText());
                                }
                        });
                }
                {
                        buttons[1] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
                        buttons[1].setBounds(146, 125, 78, 22);
                        buttons[1].setBackgroundImage(bg);
                        buttons[1].addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(buttons[1].getToolTipText());
                                }
                        });
                }
                {
                        buttons[2] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
                        buttons[2].setBounds(224, 125, 78, 22);
                        buttons[2].setBackgroundImage(bg);
                        buttons[2].addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(buttons[2].getToolTipText());
                                }
                        });
                }
                {
                        buttons[3] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
                        buttons[3].setBounds(302, 125, 78, 22);
                        buttons[3].setBackgroundImage(bg);
                        buttons[3].addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(buttons[3].getToolTipText());
                                }
                        });
                }
                {
                        buttons[4] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
                        buttons[4].setBounds(380, 125, 78, 22);
                        buttons[4].setBackgroundImage(bg);
                        buttons[4].addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                                public void mouseEnter(MouseEvent evt) {
                                        label11.setText(buttons[4].getToolTipText());
                                }
                        });
                }
                {
                        itemListener = (new SelectionAdapter() {                                
                                public void widgetSelected(SelectionEvent evt) {
                                        //ToolItem currItem = (ToolItem) evt.widget;
                                        Button currItem = (Button) evt.widget;

                                        for(int i=0;i<5;i++){
                                                buttons[i].setSelection(false);
                                                // save the index of the button that was selected
                                                if(buttons[i].equals(currItem))
                                                        selectionIndex = i+scrollIndex;
                                        }
                                        currItem.setSelection(true);
                                String node[] = (String []) currItem.getData();
                                // if current path is empty, set its name to root
                                if(text1.getText().equals(""))
                                        text1.setText(node[0]);
                                else
                                // else, update relative path
                                        text2.setText(node[0]);
                                // EXCEPTION: IF ROOT IS BOTH IN RELATIVE PATH AND CURRENT PATH, REMOVE IT FROM RELATIVE PATH
                                if(!text1.getText().contains("/") && text1.getText().equals(text2.getText()))
                                        text2.setText("");
                                String nameVal = node[0];
                                // enter Name = Value to Name/Value field
                                if(!node[1].equals(""))
                                        nameVal += " = " + node[1];
                                text3.setText(nameVal);
                                
                                try {
                                        // if no node is selected in the current node list, remove the last backslash in the current path
                                        if(!nodeSelected)
                                                fixCurrPath();
                                        // update tables
                                                renderTables();
                                                nodeSelected = true;
                                        } catch (Exception e1) {
                                                System.out.println("Failed to render tables!");
                                                //quick fix
                                                String[] arr=text1.getText().split(divider);
                                                String path="";
                                                for(int i=0;i<(arr.length-1);i++){
                                                        if(!(arr[i].equals("")))  
                                                                path+=divider+arr[i];
                                                        } 
                                                arr=text2.getText().split(divider);
                                                path+=divider+arr[0]; 
                                                text1.setText(path);  
                                                if(arr.length>2){ 
                                                        path=arr[1];
                                                        for(int i=2;i<(arr.length-1);i++){
                                                                path+=divider+arr[2];   
                                                                }
                                                        text2.setText(path); 
                                                        }
                                                if(arr.length==2){
                                                        path=arr[1]; 
                                                        text2.setText(path); 
                                                        }
                                                else{   
                                                        text2.setText(""); 
                                                        }
                                                try {
                                                        renderTables();
                                                        } catch (Exception e) {e.printStackTrace();} 
                                        }
                                }
                });
                        for(int i=0;i<5;i++){
                                buttons[i].addSelectionListener(itemListener);
                                buttons[i].setEnabled(false);
                                
                        }

                }
                {
                        label7 = new Label(sShell, SWT.NONE);
                        label7.setBounds(17, 57, 120, 19);
                        label7.setForeground(SWTResourceManager.getColor(255, 0, 0));
                        label7.setBackgroundImage(bg);
                }
                {
                        button6 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button6.setText("View Errors");
                        button6.setBounds(25, 72, 82, 22);
                        button6.setVisible(false);
                        button6.addSelectionListener(new SelectionAdapter() {
                                public void widgetSelected(SelectionEvent evt) {
                                        try {
                                                button6WidgetSelected(evt);
                                        } catch (Exception e) {e.printStackTrace();}
                                }
                        });
                }
                {
                        button7 = new Button(sShell, SWT.PUSH | SWT.CENTER);
                        button7.setText("Set");
                        button7.setEnabled(false);
                        button7.setBackgroundImage(bg);
                        button7.setBounds(481, 28, 38, 22);

                }
                {
                        list3 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
                        list3.setBounds(270, 216, 92, 207);
                        list3.setEnabled(false);
                        scroll3=list3.getVerticalBar();
                        scroll3.addListener (SWT.Selection, new Listener () {
                                public void handleEvent (Event event) {
                                        scroll4.setSelection(scroll3.getSelection());
                                        list4.setTopIndex(list3.getTopIndex());
                                }
                        });
                        list3.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                        });
                        list3.addMouseMoveListener(new MouseMoveListener() {
                                public void mouseMove(MouseEvent evt) {
                                        int element;
                                        //compute at which element of the list mouse cursor is
                                        element=scroll3.getSelection()+evt.y/list3.getItemHeight();
                                        if(element>=list3.getItemCount()){
                                                label11.setText("");
                                        }
                                        else{
                                                label11.setText(list3.getItem(element));
                                        }
                                }
                        });
                }   
                {   
                        list4 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
                        list4.setSelection(new java.lang.String[]{""});
                        list4.setBounds(370, 216, 144, 207);
                        list4.setEnabled(false);
                        scroll4=list4.getVerticalBar();
                        scroll4.addListener (SWT.Selection, new Listener () {
                                public void handleEvent (Event event) {
                                        scroll3.setSelection(scroll4.getSelection());
                                        list3.setTopIndex(list4.getTopIndex());
                                }
                        });
                        list4.addMouseTrackListener(new MouseTrackAdapter() {
                                public void mouseExit(MouseEvent evt) {
                                        label11.setText("");
                                }
                        });
                        list4.addMouseMoveListener(new MouseMoveListener() {
                                public void mouseMove(MouseEvent evt) {
                                        int element;
                                        //compute at which element of the list mouse cursor is
                                        element=scroll4.getSelection()+evt.y/list4.getItemHeight();
                                        if(element>=list4.getItemCount()){
                                                label11.setText("");
                                        }
                                        else{
                                                label11.setText(list4.getItem(element));
                                        }
                                }
                        });
                }   
                {    
                        label8 = new Label(sShell, SWT.LEFT | SWT.WRAP);
                        label8.setText("Attributes:");
                        label8.setBounds(270, 188, 92, 21);
                        label8.setBackgroundImage(bg);
                        label8.setForeground(SWTResourceManager.getColor(255,255,255));
                }    
                {     
                        label9 = new Label(sShell, SWT.LEFT | SWT.WRAP);
                    label9.setText("Values:");
                    label9.setBounds(370, 188, 101, 21);
                    label9.setBackgroundImage(bg);
                    label9.setForeground(SWTResourceManager.getColor(255,255,255));
                } 
                {
                        label10 = new Label(sShell, SWT.CENTER);
                        label10.setBounds(17, 2, 492, 20);
                        label10.setForeground(SWTResourceManager.getColor(0, 255, 0));
                        label10.setBackgroundImage(bg);
                }
                {
                        label11 = new Label(sShell, SWT.LEFT | SWT.BORDER);
                        label11.setBounds(0, 462, 536, 19);
                }
        }
        //Open XML
        private void button1WidgetSelected(SelectionEvent evt) throws Exception {
                FileDialog fd=new FileDialog(sShell, SWT.OPEN);
                // open file dialog for xml files
                fd.setFilterExtensions(new String[]{"*.xml"});
                xmlFile=fd.open();
                System.out.println(xmlFile);
                if(xmlFile!=null){
                        File xmlf = new File(xmlFile);
                        // check if file exists
                        if(xmlf.exists()){
                                // enable screen
                                text1.setEnabled(true);
                                text2.setEnabled(true);
                                text3.setEnabled(true);
                                button2.setEnabled(true);
                                button5.setEnabled(true);
                                button7.setEnabled(true);
                                list1.setEnabled(true);
                                list2.setEnabled(true);
                                list3.setEnabled(true);
                                list4.setEnabled(true); 
                                //fix for the texts keeping stuff when opening new XML
                                //clear the pathes
                                text1.setText("");
                                text2.setText("");
                                text3.setText("");
                                label7.setText("");
                                label10.setText("");
                                //clear the lists
                                list1.removeAll();
                                list2.removeAll();
                                list3.removeAll();
                                list4.removeAll();
                                //clear the nodes list
                                for(int i=0;i<5;i++){
                                        buttons[i].setText("");
                                        buttons[i].setEnabled(false);
                                }
                                // load xml file
                                loadXML();
                                label10.setText("XML File: " + xmlf.toString());
                                label10.setToolTipText(xmlf.toString());
                        }
                }
        }
        //Forward
        private void button5WidgetSelected(SelectionEvent evt) throws Exception {
                if(list1.getSelectionCount()!=0){
                        String path=text2.getText();
                        path+=divider+list1.getSelection()[0];
                        text2.setText(path);
                        String fullpath=text1.getText()+divider+path;
                        Node cur=getResult(fullpath).item(0);
                        String value=getAttribute(cur);
                        if(value==null) 
                                text3.setText(list1.getSelection()[0]);
                        else{  
                                text3.setText(list1.getSelection()[0]+" = "+value);
                                } 
                        renderTables();
                }
        }
        

        //Back
        private void button2WidgetSelected(SelectionEvent evt) throws Exception {
                if(text2.getText()!=""){
                        String cur=text2.getText();
                        //split the expression and get the last instance
                        String[] list=cur.split(divider);
                        String todel=list[list.length-1];
                        //construct the new expression
                        if((cur.length()-todel.length()-1)>=0){
                                String newexpr=cur.substring(0, cur.length()-todel.length()-1);
                                text2.setText(newexpr);
                                text3.setText(newexpr.split(divider)[newexpr.split(divider).length-1]);
                                renderTables();
                        }
                        else{
                                text2.setText("");
                                text3.setText(curRoot.getLocalName());
                                //Render a new tables for current subroot
                                renderTables();
                        }
                }
        }
        
        //Right arrow
        private void button4WidgetSelected(SelectionEvent evt) throws Exception {
                // move right only if there are nodes that do not fit the screen
                int amount = currNodes.size();
                if(amount>5 && scrollIndex+5<amount){
                        // save item's contents as Previous Node
                        scrollIndex++;
                        // move button nodes left by one position
                        for(int i=0;i<4;i++){
                                buttons[i].setText(buttons[i+1].getText());
                                buttons[i].setData(buttons[i+1].getData());
                                buttons[i].setSelection(false);
                                buttons[i].setToolTipText(buttons[i].getText());
                        }
                        
                        button3.setEnabled(true);
                        // change right arrow button to disabled if no more nodes to the right 
                        if(scrollIndex+5>=amount)
                                button4.setEnabled(false);
                        // add new node to last button                          
                        String node[] = getNextNode(((String[])buttons[3].getData())[0]);
                        // check if there is value
                        if(!node[1].equals(""))
                                buttons[4].setText(node[0] + " = " + node[1]);
                        // else, display the node name
                        else
                                buttons[4].setText(node[0]);
                        buttons[4].setData(node);
                        buttons[4].setSelection(false);
                        buttons[4].setToolTipText(buttons[4].getText());
                        // if selected node is in the scrolling range, update selection of node
                        if(selectionIndex >= scrollIndex && selectionIndex <= scrollIndex+4)
                                buttons[selectionIndex-scrollIndex].setSelection(true);
                }
        }
        
        //Left arrow
        private void button3WidgetSelected(SelectionEvent evt) throws Exception {
                // move left only if there are nodes that do not fit the screen
                int amount = currNodes.size();
                if(amount>5 && scrollIndex>0){
                        // Save last button node as the Next Node
                        // increment the scrollIndex (moved right)
                        scrollIndex--;
                        button4.setEnabled(true);
                        // change left arrow button to disabled if no more nodes to the left
                        if(scrollIndex==0)
                                button3.setEnabled(false);
                        //      move button contents right
                        for(int i=4;i>0;i--){
                                buttons[i].setText(buttons[i-1].getText());
                                buttons[i].setData(buttons[i-1].getData());
                                buttons[i].setSelection(false);
                                buttons[i].setToolTipText(buttons[i].getText());
                        }
                        // add new node to first button
                        String node[] = getPrevNode(((String[])buttons[1].getData())[0]);
                        // check if there is value
                        if(!node[1].equals(""))
                                buttons[0].setText(node[0] + " = " + node[1]);
                        // else, display the node name
                        else
                                buttons[0].setText(node[0]);
                        buttons[0].setData(node);
                        buttons[0].setSelection(false);
                        buttons[0].setToolTipText(buttons[0].getText());
                        // if selected node is in the scrolling range, update selection of node
                        if(selectionIndex >= scrollIndex && selectionIndex <= scrollIndex+4)
                                buttons[selectionIndex-scrollIndex].setSelection(true);
                }
        }
        
        // Errors button
        private void button6WidgetSelected(SelectionEvent evt) throws Exception {
                JOptionPane.showMessageDialog(null,errors);     
        }

        // Focus lost on Current Path button
        private void text1FocusLost(FocusEvent evt) {
                Runnable errorFocus = new Runnable() {public void run() {text1.setFocus();}};
                if(text1.getText().equals("")){
                        JOptionPane.showMessageDialog(null,"Current Path cannot be empty!");
                    Display.getCurrent().asyncExec(errorFocus);
                }
                else if(!text1.getText().equals(prevPath)){             
                        try {
                                text2.setText("");
                                text3.setText("");
                                // no nodes selected
                                nodeSelected = false;
                                renderNodeList();
                        } catch (Exception e) {
                                JOptionPane.showMessageDialog(null,"Illegal XML Path. Try again!");
                                // Get focus to text
                                Display.getCurrent().asyncExec(errorFocus);
                        }       
                }
        }
        
        private void text1FocusGained(FocusEvent evt) {
                prevPath = text1.getText();
        }
        
        
        /*
         *
         *    XPATH FUNCTIONS
         *
         */
        
        
        private void loadXML() throws Exception{
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                factory.setNamespaceAware(true);
                factory.setValidating(true);
                DocumentBuilder builder;
                builder = factory.newDocumentBuilder();
                builder.setErrorHandler(new org.xml.sax.ErrorHandler() {
                        //To handle Fatal Errors
                        public void fatalError(SAXParseException exception)throws SAXException {
                                if(dtd.equals(""))
                                label7.setText("XML file is invalid!");
                                else
                                label7.setText("DTD file is invalid!");
                                errors.concat("Line: " +exception.getLineNumber() + "\nFatal Error: "+exception.getMessage()+"\n");
                        }
                        //To handle Errors
                        public void error(SAXParseException e)throws SAXParseException {
                                errors.concat("Line: " +e.getLineNumber() + "\nError: "+e.getMessage()+"\n");
                        }
                        //To Handle warnings
                        public void warning(SAXParseException err)throws SAXParseException{
                                errors.concat("Line: " +err.getLineNumber() + "\nWarning: "+err.getMessage()+"\n");
                        }
                        });
                doc = builder.parse(xmlFile);
        DocumentType docType = doc.getDoctype();
        if(docType==null)
                label7.setText("No Doctype declared");
        else {
                dtd =  docType.getSystemId();
                // if XML has no DTD
                if(dtd==null){
                        label7.setText("XML file has no DTD");
                }
                // validate DTD
                else {
                        File file = new File(xmlFile);
                        if(!file.exists())
                                label7.setText("DTD file not found");
                        else
                        {
                                dtd = file.getAbsolutePath() + java.io.File.separator + dtd;
                                DOMSource source = new DOMSource(doc);        
                                StreamResult result = new StreamResult(System.out);
                                TransformerFactory tf = TransformerFactory.newInstance();
                                Transformer transformer = tf.newTransformer();
                                transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtd);
                                transformer.transform(source, result);
                        }
                }
        }
                // load XML

                XPathFactory xf = XPathFactory.newInstance();
                XPath xpath = xf.newXPath();
                
                // get root
                XPathExpression expr = xpath.compile("node()");
                NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);

                // set Root node
                curRoot = (Element) nodes.item(0);
                String root = curRoot.getLocalName();
                String node[] = { root, "" };
                // set first button to be the root node
                buttons[0].setText(root);
                buttons[0].setData(node);
                buttons[0].setEnabled(true);
                buttons[0].setToolTipText(root);
                currNodes.put(node[0],node[1]);
                buttons[0].notifyListeners(SWT.Selection, new Event());
        }

        // retrieves the next node in the hash map
        private String[] getNextNode(String nodeName){
                Iterator<Entry<String,String>> iter = currNodes.entrySet().iterator();          
                Entry<String,String> entry;
                String[] node = { "", "" };
                // find the given node
                while(iter.hasNext() && !iter.next().getKey().equals(nodeName)){}
                // save next node
                if(iter.hasNext()){
                        entry = iter.next();
                        node[0] = entry.getKey();
                        node[1] = entry.getValue();
                }
                // return next node
                return node;
                        
        }
        // return the previous node in the Current Nodes hash
        private String[] getPrevNode(String nodeName){
                Iterator<Entry<String,String>> iter = currNodes.entrySet().iterator();          
                Entry<String,String> entry1=null, entry2 = null;
                String[] node = { "", "" };
                if(iter.hasNext()){
                        entry1 = iter.next();
                }
                // search for the node
                while(iter.hasNext() && entry1!=null && !entry1.getKey().equals(nodeName)){
                        // save previous node
                        entry2 = entry1;
                        entry1 = iter.next();
                }
                // return previous node
                node[0] = entry2.getKey();
                node[1] = entry2.getValue();
                return node;
        }
        
        // fills the toolbar with retrieved items
        // returns the amount of added items to the toolbar
        private int renderNodeButtons(){
                Entry<String,String> entry;
        // maximum 8 items in the toolbar
                int i=0;
                String name, value;
                for(i=0;i<5;i++){
                        buttons[i].setSelection(false);
                }
                // amount of nodes that were found
                int nodes = currNodes.size();
                i = 0;
                // check if needs to enable the right arrow (more nodes than fit on the screen)
                if(nodes>5){
                        button4.setEnabled(true);
                }
                // get minimum amount of nodes to be added to node buttons
                int size = Math.min(nodes,5);
                if(size>0){
                        // add up to 5 nodes to node buttons
                        Iterator<Entry<String,String>> iter = currNodes.entrySet().iterator();
                        while(iter.hasNext() && i<size){
                                entry = iter.next();
                                name = entry.getKey();
                                value = entry.getValue();
                                
                        String node[] = { name, value };
                                if(!value.equals(""))
                                        buttons[i].setText(name + " = " + value);
                                // else, display the node name
                                else
                                        buttons[i].setText(name);
                        // set item Data text
                        buttons[i].setData(node);
                        buttons[i].setEnabled(true);
                                buttons[i].setToolTipText(buttons[i].getText());
                        //items.add(item);
                                i++;
                        }

                }
                // empty the rest of the buttons
                while(i<5){
                        buttons[i].setText("");
                        buttons[i].setToolTipText("");
                        buttons[i].setData(null);
                        buttons[i].setEnabled(false);
                        i++;
                }
                return size;
        }       
        /*
         * receives a relative path from the root and compiles the path returning a list of nodes as a result
         */
        private NodeList getResult(String relativePath) throws Exception
        {
                //create an XPath factory
                XPathFactory factory = XPathFactory.newInstance();
                //create an XPath Object
                XPath xpath = factory.newXPath();
                //make the XPath object compile the XPath expression
                XPathExpression expr = xpath.compile(relativePath);
                return (NodeList) expr.evaluate(doc, XPathConstants.NODESET);           
                
        }
        
        // receives a list of nodes and builds a hash map of node attributes
        private HashMap<String,Integer> nodesToHashMap(NodeList nodes)
        {
                HashMap<String, Integer> hMap=new HashMap<String, Integer>();
                //populate the hash and identify the double instances
                for(int i=0;i<nodes.getLength();i++){
                        if(nodes.item(i).getLocalName()!=null){
                                String name=nodes.item(i).getNodeName();
                                if(hMap.get(name)==null){
                                        Integer instance=new Integer(0);
                                        hMap.put(name, instance);
                                }
                                else{
                                        Integer val=hMap.get(name);
                                        if(val==0){
                                                val=1;
                                                hMap.remove(name);
                                                hMap.put(name, val);
                                        }
                                }
                        }
                }       
                return hMap;
        }
        
        // fill the toolbar of currentPath's direct children (Current node list)
        private void renderNodeList() throws Exception{
                NodeList nodes;
                // make sure that there is a relative path
                String path = text1.getText();
                if(path.trim().equals(""))
                        path = "node()";
                nodes = getResult(path);
                String name, value;
                // illegal path
                if(nodes.getLength()==0)
                        JOptionPane.showMessageDialog(null,"Illegal XML Path. Try again!");             
                else{           
                        currNodes.clear();
                        // get a map of all nodes and values
                        TreeMap<String,String> nodesHash = getNodeAttrHash(nodes);
                        for (Map.Entry<String,String> entry : nodesHash.entrySet()) {
                                // put all nodes and values into a treemap
                                name = entry.getKey();
                                value = entry.getValue();
                                currNodes.put(name,value);
                        }
        
                        // no nodes found, write value inside Name / Text
                        if(renderNodeButtons()==0)
                                text3.setText(nodes.item(0).getNodeValue());
                    list1.removeAll();
                    list2.removeAll();
                }
        }
        
        // get a hash map of Node names with enumeration and its attributes if exist
        private TreeMap<String,String> getNodeAttrHash(NodeList nodes){
                // get hash map of node names and counter of its appearances
                TreeMap<String,String> nodesHash = new TreeMap<String,String>();
                HashMap<String, Integer> hMap = nodesToHashMap(nodes);
                String nodeName, attr;
                // populate lists of attributes and nodes
                for (int i = 0; i < nodes.getLength(); i++) {
                        // some XMLs contain illegal nodes which are carriage return chars \n\t they should be ignored
                        if(nodes.item(i).getLocalName()!=null){
                                String name=nodes.item(i).getLocalName();
                                if(name!=null){
                                        Integer val=hMap.get(name);
                                        if(val==0){//only one with this name
                                                nodeName = name;
                                        }
                                        else{//several with this name
                                                nodeName = name+"["+val+"]";
                                                val++;
                                                hMap.remove(name);
                                                hMap.put(name, val);
                                        }
                                        String value = getAttribute(nodes.item(i));
                                        if(value!=null)
                                                attr = value;
                                        else
                                                attr = "";
                                        nodesHash.put(nodeName, attr);
                                }
                        }
                }
                return nodesHash;
        }
        
        // remove last value in the current path so that with relative path it would be a legal XPATH string
        private void fixCurrPath(){
                String path = text1.getText();
                int index = path.lastIndexOf("/");
                if(index>=0)
                        text1.setText(path.substring(0,path.lastIndexOf("/")));
        }
        
        private void renderTables() throws Exception{
                /*
                 * fills the element and attribute tables according to relative path    
                 */
                        NamedNodeMap nnm=null;
                        NodeList nodes;
                        list1.removeAll();
                        list2.removeAll();
                        list3.removeAll();   
                        list4.removeAll(); 
                        if(!text1.getText().equals("") || !text2.getText().equals("")){//need to consider the relative path
                                String path;
                                if(text2.getText().equals(""))
                                        path = text1.getText();
                                else
                                    path = text1.getText()+ "/" + text2.getText();
                                nodes = getResult(path+"/node()");
                                nnm=renderNNM(path+"/node()");
                        }
                        else{
                                nodes = curRoot.getChildNodes();
                                nnm=curRoot.getAttributes();
                        }
                        TreeMap<String,String> nodesHash = getNodeAttrHash(nodes);
                        for (Map.Entry<String,String> entry : nodesHash.entrySet()) { 
                            list1.add(entry.getKey());
                            list2.add(entry.getValue());
                        } 
                        //populating attributes
                        for(int i=0;i<nnm.getLength();i++){  
                                list3.add(nnm.item(i).getLocalName()); 
                                if(nnm.item(i).getNodeValue()!=null) 
                                        list4.add(nnm.item(i).getNodeValue());  
                                else      
                                        list4.add(""); 
                        }     
                }  
        /* 
         * Returns map of attributes of the node at given path 
         */      
        private NamedNodeMap renderNNM(String path) throws Exception {   
                NodeList list=getResult(path);   
                return list.item(0).getParentNode().getAttributes();  
        } 

        // get a node and return its attribute, if it has any
        private String getAttribute(Node node){
                // if node is attribute, display CDATA
                NodeList children = node.getChildNodes();
                if(children.getLength()==1){
                        Node child = children.item(0);
                        if(child.getNodeType() == Node.TEXT_NODE)
                                return(child.getNodeValue());
                }
                return null;
        }
}
